﻿using System;
using System.Drawing.Imaging;
using System.IO;
using System.Linq;
using System.Windows.Media.Imaging;
using agsXMPP;
using agsXMPP.protocol.client;
using agsXMPP.protocol.iq.roster;
using agsXMPP.protocol.iq.vcard;
using Mammoth.Entities;
using Mammoth.Events;

namespace Mammoth.Services
{
    public partial class GTalkService
    {
        private XmppClientConnection GetXmppClient(string serviceEmail)
        {
            XmppClientConnection client;
            if (!clients.TryGetValue(serviceEmail, out client))
            {
                client = new XmppClientConnection();
                client.AutoAgents = false;
                client.AutoPresence = true;
                client.AutoRoster = true;
                client.AutoResolveConnectServer = true;

                client.OnLogin += client_OnLogin;
                client.OnMessage += client_OnMessage;
                client.OnRosterItem += client_OnRosterItem;
                client.OnRosterEnd += client_OnRosterEnd;
                client.OnPresence += client_OnPresence;

                client.OnClose += client_OnClose;
                client.OnAuthError += client_OnAuthError;
                client.OnSocketError += client_OnSocketError;
                client.OnStreamError += client_OnStreamError;
                clients[serviceEmail] = client;
            }

            return client;
        }

        private void ReleaseClient(XmppClientConnection client)
        {
            client.OnLogin -= client_OnLogin;
            client.OnMessage -= client_OnMessage;
            client.OnRosterItem -= client_OnRosterItem;
            client.OnRosterEnd -= client_OnRosterEnd;
            client.OnPresence -= client_OnPresence;

            client.OnClose -= client_OnClose;
            client.OnAuthError -= client_OnAuthError;
            client.OnSocketError -= client_OnSocketError;
            client.OnStreamError -= client_OnStreamError;
        }

        string GetServiceEmail(XmppClientConnection client)
        {
            return client.MyJID.Bare;
        }

        void client_OnClose(object sender)
        {
            var serviceEmail = GetServiceEmail((XmppClientConnection)sender);
            //OnError(serviceEmail, ServiceErrorType.AuthenticationError);
        }

        void client_OnStreamError(object sender, agsXMPP.Xml.Dom.Element e)
        {
            SendError(sender, ServiceErrorType.ConnectionError);
        }

        void client_OnSocketError(object sender, Exception ex)
        {
            SendError(sender, ServiceErrorType.ConnectionError);
        }

        void client_OnAuthError(object sender, agsXMPP.Xml.Dom.Element e)
        {
            SendError(sender, ServiceErrorType.AuthenticationError);
        }

        private void SendError(object sender, ServiceErrorType type)
        {
            var serviceEmail = GetServiceEmail((XmppClientConnection)sender);
            var acc = AccountList.FirstOrDefault(x => x.Email == serviceEmail);
            acc.State = AccountState.Logoff;
            OnError(serviceEmail, type);
        }

        void client_OnPresence(object sender, agsXMPP.protocol.client.Presence pres)
        {

            if (pres.Type == agsXMPP.protocol.client.PresenceType.subscribe)
            {
                var serviceEmail = GetServiceEmail((XmppClientConnection)sender);
                BuddyList.Add(new BuddyEntity()
                {
                    SubscriptionType = SubscriptionType.none,
                    ServiceEmail = serviceEmail,
                    Email = pres.From.Bare
                });
                OnSubscriptionRequest(serviceEmail, pres.From.Bare);
                OnFriendListLoad(serviceEmail);
            }
            else
            {
                var serviceEmail = GetServiceEmail((XmppClientConnection)sender);
                var account = AccountList.FirstOrDefault(x => x.Email == serviceEmail);
                if (account != null)
                {
                    account.PresenceType = pres.Type;
                    if (!string.IsNullOrEmpty(pres.Status))
                        account.Status = pres.Status;
                    GetVCard(account, GetXmppClient(serviceEmail));
                }
                var buddy = BuddyList.FirstOrDefault(x => x.Email == pres.From.Bare & x.ServiceEmail == serviceEmail);
                if (buddy != null)
                {
                    buddy.PresenceType = pres.Type;
                    if (!string.IsNullOrEmpty(pres.Status))
                        buddy.Status = pres.Status;
                    if (buddy.SubscriptionType == SubscriptionType.none)
                        buddy.SubscriptionType = SubscriptionType.both;
                    GetVCard(buddy, GetXmppClient(buddy.ServiceEmail));
                }
            }
        }

        private void GetVCard(IGTalkAccountEntity buddy, XmppClientConnection client)
        {
            if (buddy.Avatar != null) return;
            VcardIq viq = new VcardIq(IqType.get, new Jid(buddy.Email));
            client.IqGrabber.SendIq(viq, new IqCB(
                (s, iq, data) =>
                {
                    Vcard card = iq.Vcard;
                    buddy.Name = card.Fullname;
                    App.Current.Dispatcher.Invoke(() =>
                    {
                        if (card.Photo != null)
                            buddy.Avatar = GetMediaImage(card.Photo.Image);
                    });
                }
                ), null);
        }

        private BitmapImage GetMediaImage(System.Drawing.Image image)
        {
            using (MemoryStream m = new MemoryStream())
            {
                image.Save(m, ImageFormat.Jpeg);
                m.Position = 0;
                var result = new BitmapImage();
                result.BeginInit();
                result.StreamSource = m;
                result.CacheOption = BitmapCacheOption.OnLoad;
                result.EndInit();
                return result;
            }
        }

        void client_OnRosterEnd(object sender)
        {
            var serviceEmail = GetServiceEmail((XmppClientConnection)sender);
            OnFriendListLoad(serviceEmail);

        }

        void client_OnRosterItem(object sender, agsXMPP.protocol.iq.roster.RosterItem item)
        {
            var serviceEmail = GetServiceEmail((XmppClientConnection)sender);
            var buddy = new BuddyEntity();
            buddy.Email = item.Jid.Bare;
            buddy.ServiceEmail = serviceEmail;
            buddy.SubscriptionType = item.Subscription;
            BuddyList.Add(buddy);

        }

        void client_OnMessage(object sender, agsXMPP.protocol.client.Message msg)
        {
            var serviceEmail = GetServiceEmail((XmppClientConnection)sender);
            OnMessage(serviceEmail, msg.From.Bare, msg.Body);
        }

        void client_OnLogin(object sender)
        {
            var serviceEmail = GetServiceEmail((XmppClientConnection)sender);
            var account = AccountList.FirstOrDefault(x => x.Email == serviceEmail);
            if (account != null)
                account.State = AccountState.Login;
            OnLogin(serviceEmail);
        }
    }
}
